import 'dart:async';

void main() {
//  testFuture01();
//  testFuture02();
//  testWhenComplete();
//  testHellCallback();
//  testFuture03();
//  testFuture04();
//  testFuture05();

//------------------------------
//  testNull();
//  testMixins01();
//  testMixins02();

//---------------------------

//  testStream01();
//  testStream02();
//  testStreamWhere();
//  testStreamMap();

//  Bf().listen((value) {}, onError: () {}, onDone: () {});

//  testPhoneNumberRegex();
  testNumbers();
}

/// 基础原理的实验
///
/// Dart是基于单线程模型的语言，在dart中有一个很重要的概念叫做isolate(孤岛，隔离)，一个isolate可以是线程也可以是进程具体看dart的实现
///
/// 通常情况下我们的代码都是在main isolate中运行的（可以近视的看作为android中的main thread）
///
/// 这个例子都是学习Future的，Future为 未来执行的操作，一般是"异步"的
///
///

void testFuture01() {
  Future.delayed(Duration(seconds: 1), () {
    return "delay 1 seconds";
  }).then((data) {
    print("test future01 $data");
  });
}

void testFuture02() {
  Future.delayed(Duration(seconds: 1), () {
    return "testFuture02";
  }).then((data) {
    throw AssertionError("$data error");
  }).catchError((e) {
    print(e);
  });
}

void testWhenComplete() {
  Future.delayed(Duration(seconds: 1), () {
    return "testWhenComplete";
  }).then((value) {
    throw AssertionError(" $value error");
  }).catchError((e) {
    print(e);
  }).whenComplete(() {
    print("Future complete");
  });
}

/// 模拟场景，先登录--> 根据用户id请求用户数据-->保存数据

Future<String> login(String userName, String password) {
  return Future<String>.delayed(Duration(milliseconds: 500), () {
    String userId = userName + password;
    print("login");
    return userId;
  });
}

Future<String> getUserInfo(String userId) {
  return Future<String>.delayed(Duration(milliseconds: 500), () {
    print("getUserInfo");
    return "userInfo userid = $userId";
  });
}

Future<bool> savaUserInfo(String userInfo) {
  return Future<bool>.delayed(Duration(milliseconds: 500), () {
    print("savaUserInfo");
    return true;
  });
}

///测试地狱回调
void testHellCallback() {
  login("tian", "123456").then((id) {
    getUserInfo(id).then((userinfo) {
      savaUserInfo(userinfo);
    });
  });
}

///避免上面的地狱回调
void testFuture03() async {
  String userId = await login("tian", "123456");
  String userInfo = await getUserInfo(userId);
  bool isSaveSuccess = await savaUserInfo(userInfo);

  print("savae userinfo $isSaveSuccess");
}

void testFuture04() {
  print('main #1 of 2');
  scheduleMicrotask(() => print('microtask #1 of 2'));
  new Future.delayed(
      new Duration(seconds: 1), () => print('future #1 (delayed)'));
  new Future(() => print('future #2 of 3'));
  new Future(() => print('future #3 of 3'));
  scheduleMicrotask(() => print('microtask #2 of 2'));
  print('main #2 of 2');
}

void testFuture05() {
  print('main #1 of 2');
  scheduleMicrotask(() => print('microtask #1 of 3'));

  new Future.delayed(
      new Duration(seconds: 1), () => print('future #1 (delayed)'));

  new Future(() => print('future #2 of 4'))
      .then((_) => print('future #2a'))
      .then((_) {
    print('future #2b');
    scheduleMicrotask(() => print('microtask #0 (from future #2b)'));
  }).then((_) => print('future #2c'));

  scheduleMicrotask(() => print('microtask #2 of 3'));

  new Future(() => print('future #3 of 4'))
      .then((_) => new Future(() => print('future #3a (a new future)')))
      .then((_) => print('future #3b'));

  new Future(() => print('future #4 of 4'));
  scheduleMicrotask(() => print('microtask #3 of 3'));
  print('main #2 of 2');
}

/// 操作符"??"的用法，A ?? B 表示如果A为null使用B，如果A不为null使用A
void testNull() {
  String person;
  String name;
  String nickName = "nickName";
  print(person ?? name ?? nickName);
}

/// ---------------------------Mixins (混入的学习理解)---------------------------------
/// 概念：在面响对象的语言中 mixins类是一个把自己的属性方法提供给其他类使用，但却不需要成其他类的父类
/// mixins的条件
/// mixins类只能继承自Object,而且不能有构造函数
///
///
class A {
  void a() {
    print("a");
  }
}

class A1 {
  String content = "10";

  void a() {
    print("a1");
  }
}

class B with A, A1 {}

class B1 with A1, A {}

class B2 with A, A1 {
  void a() {
    print("b2");
  }
}

class C {
  void a() {
    print("c");
  }
}

class B3 extends C with A, A1 {}

class B4 extends C with A1, A {}

class B5 extends C with A, A1 {
  void a() {
    print("b5");
  }
}

class D with A1 {}

void testMixins01() {
  D b = D();
  b.a();

  print(b is A1);
  b.content = "112";
}

///一个类可以 mixins多个类，但是如果mixins的类有相同的方法，会出现什么结果?
///
/// 当几个类中有同名方法时，通过下面方法测试得到结论
/// 1、当B类有a()方法时，调用自己的a()方法。不管extends 和 with
/// 2、当B类无a()方法时，优先调用mixins类的a()方法，当存在多个类被mixins时，会采取with顺序靠后的类的方法
///
void testMixins02() {
  B b = new B();
  B1 b1 = new B1();
  B2 b2 = new B2();
  B3 b3 = new B3();
  B4 b4 = new B4();
  B5 b5 = new B5();

  b.a();
  b1.a();
  b2.a();
  b3.a();
  b4.a();
  b5.a();
}

/// --------------------------------implements的用法---------------------------------------
///
/// 1、每一个class 都是一个隐式的接口，这个接口包含类里所有的属性和方法(疑问 私有的属性和方法也包含吗？ 包含 )
/// 2、当class被当成interface使用的时候，class中的方法需要在子类中实现，class的属性也需要在子类中实现
///

void testImplements() {
  //可以看到Students类实现了所有Person类的方法和属性无论是不是私有的
  Students students = Students();
}

class Person {
  String name;
  String _nickName;

  Person(this.name);

  void thinkSomething() {
    print("persion public methods");
  }

  void _buildWorld() {
    print("persion private methods");
  }
}

class Students implements Person {
  @override
  String _nickName;

  @override
  String name;

  @override
  void _buildWorld() {
    // TODO: implement _buildWorld
  }

  @override
  void thinkSomething() {
    // TODO: implement thinkSomething
  }
}

/// 学习Stream用法 ---------------------------
///
///

void testStream01() {
//利用 Stream.fromFuture来创建流
//  Stream.fromFuture(Future<String>.delayed(Duration(seconds: 1)).then((result) {
//    return "test steam01";
//  })).listen((data) {
//    print(data);
//  }, onError: (error) {
//    print(error);
//  }, onDone: () {
//    print('onDone');
//  }, cancelOnError: true);

  //使用StreamController来创建流
  StreamController controller = StreamController();
  controller.sink.add(123);
  controller.sink.add("xyz");
  controller.sink.add(false);

  controller.stream.listen((data) {
    print(data);
  });
}

//流的转换（猜数游戏）
void testStream02() {
  StreamController<int> controller = StreamController<int>();
  StreamTransformer<int, String> streamTransformer =
      StreamTransformer<int, String>.fromHandlers(handleData: (value, sink) {
    if (value == 100) {
      sink.add("你猜对了");
    } else {
      sink.addError("还没有猜中，请再猜一次");
    }
  });

  controller.stream.transform(streamTransformer).listen((data) {
    print(data);
  }, onError: (error) {
    print('error:$error');
  });

  controller.sink.add(10);
  controller.sink.add(100);
}

/// 测试.where
void testStreamWhere() {
  ///where是条件过滤，只有符合条件的事件才发送
  ///这里代码执行的结果是
  ///11
  ///8
  ///9
  ///10
  ///接收到10
  StreamController<int> controller = StreamController();
  controller.stream.where((variant) {
    print(variant);
    if (variant == 10) {
      return true;
    } else {
      return false;
    }
  }).listen((data) {
    print('接收到$data');
  });

  controller.sink.add(11);
  controller.sink.add(8);
  controller.sink.add(9);
  controller.sink.add(10);
}

///测试Stream的map变换
void testStreamMap() {
  StreamController<int> controller = StreamController();
  //map 是改变事件类型 Transforms each element of this stream into a new stream event.
  controller.stream.map((value) {
    return '$value + 1';
  }).listen((String data) {
    print(data);
  });

  controller.sink.add(10);
  controller.sink.add(23);
  controller.sink.add(12);

//  StreamController<int> controller = StreamController();
//  controller.stream
//      .join('10')
//      .listen((data) {
//    print(data);
//  });
//
//  controller.sink.add(10);
//  controller.sink.add(23);
//  controller.sink.add(12);
}

void testStreamOther() {}

class Bf {
  void listen(void onData(T), {Function onError, Function onDone}) {}
}

 void testPhoneNumberRegex(){
   RegExp _phoneNumberReExp = RegExp(
       r'^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(147))\d{8}$');
  
   print(_phoneNumberReExp.hasMatch('11488940007'));

 }
 
 
 void testNumbers(){
   int target = 1;
   int result = (target / 3).ceil();
   print('result--$result');
   
//   String test = null ;
//
//   print('test-is-${test.isEmpty}');
   
   int microsecondsSinceEpoch = 1561084146000;
   
   DateTime date = DateTime.fromMillisecondsSinceEpoch(microsecondsSinceEpoch);
   print(date);
   print('${date.year}-${date.month}-${date.day} ${date.hour}:${date.minute}');

  //---------解析URI-----
  String uri = 'card://caseList?directIdsStr=164&dire=11';
  Uri mUri = Uri.dataFromString(uri);

  print('parameter --- \'directIdsStr\' ---${mUri.queryParameters['directIdsStr']}');

  String idCard = '513922198803085631';
  
  String aa = idCard.replaceAll(RegExp(r'(\d{6})\d{8}(\w{4})'),  r'$1*****$2');

  print(aa);

}

